---
title: AddUser
summary: Creates a new external-domain Active Directory account, gated by the IP allow-list.
status: draft
owner: "Not determined from source"
last_reviewed: 2026-09-22
---

# AddUser (OP-02)

## Request and response

| Part | Type | Description |
| --- | --- | --- |
| `inUserId` | `String` | The new account's `SamAccountName` and `DisplayName`. |
| `inPassword` | `String` | The initial password. When empty, a hard-coded default literal is substituted ([BR-10](../business-rules.md#br-10-an-empty-password-is-replaced-with-a-hard-coded-default)) — the value is never reproduced in this documentation. |
| `inName` | `String` | The account's `Name` property. |
| `inGivenName` | `String` | The account's `GivenName` property. |
| `inSurName` | `String` | The account's `Surname` property. |
| `inDescription` | `String` | The account's `Description` property. |
| `inPhoneNum` | `String` | Written to `telephoneNumber` only when non-empty ([BR-13](../business-rules.md#br-13-an-optional-attribute-is-written-only-when-supplied)). |
| `inMailAddr` | `String` | Written to `mail` only when non-empty. |
| `inTitle` | `String` | Written to `title` only when non-empty. |
| `inInfo` | `String` | Written to `info` only when non-empty. |
| `inCompany` | `String` | Written to `company` only when non-empty. |
| `inFAXNum` | `String` | Written to `facsimileTelephoneNumber` only when non-empty. |
| `inDivision` | `String` | Written to `division` only when non-empty. |

| Part | Type | Description |
| --- | --- | --- |
| `<return>` | `ADServiceResponse` | `Response` is `Success`, `Failure`, or `AccessDenied`'s `Failure`. `Message` carries the caught exception text on a `Failure`, otherwise empty. |

## WebMethod attributes

`<WebMethod()>` — bare, no arguments supplied.

## Steps

1. `CheckAccess()`; if `HasAccess` is `False`, return `AccessDenied()` ([BR-01](../business-rules.md#br-01-mutating-and-password-operations-require-an-approved-caller)).
2. Compute the target container `"CN=Users," & CONTAINER_EXT` ([BR-09](../business-rules.md#br-09-a-new-account-is-created-in-the-cn%3Dusers-container)).
3. Call H1 `GetContext` for the external domain; the result is discarded and rebuilt at step 6.
4. Initialize the response sentinel to `Success` with an empty message.
5. Call H2 `GetUserPrincipal` for the external domain to test for an existing account.
   - If a principal is found, set `Response = UserExists`, then **immediately overwrite** it with `Response = Failure`, and skip to step 13 ([BR-12](../business-rules.md#br-12-an-existing-account-is-not-re-created)) — the `UserExists` code is assigned but never reaches the wire (tech debt TD-17, see [Tech debt](../tech-debt.md)).
6. Otherwise rebuild the context scoped to the target container and construct `New UserPrincipal(prinContext)`.
7. If `inPassword` is empty, substitute the hard-coded default password literal ([BR-10](../business-rules.md#br-10-an-empty-password-is-replaced-with-a-hard-coded-default)) — the literal is a known shared credential and is never reproduced in this documentation (see [Authentication and authorization](../authentication-authorization.md) and [Tech debt](../tech-debt.md)).
8. Populate `GivenName`, `Surname`, `DisplayName = inUserId`, `Name = inName`, `SamAccountName = inUserId`, `SetPassword(inPassword)`, `ScriptPath = " "`, `Description`, and `Enabled = True` ([BR-11](../business-rules.md#br-11-a-new-account-is-provisioned-enabled-with-fixed-identity-fields)).
9. `userPrin.Save()` inside `Try`.
   - On exception, set `Response = Failure`, `Message = ex.Message` — and **continue** into the `DirectoryEntry` block below, operating on an unsaved principal (tech debt TD-18, HIGH — see [Tech debt](../tech-debt.md)).
10. When the underlying object is a `DirectoryEntry`, write `company`, `telephoneNumber`, `mail`, `info`, `title`, `facsimileTelephoneNumber`, and `division`, each only when the matching input is non-empty ([BR-13](../business-rules.md#br-13-an-optional-attribute-is-written-only-when-supplied)).
11. `dirEntry.CommitChanges()` inside `Try`.
    - On exception, set `Response = Failure`, `Message = ex.Message`.
12. `Finally` releases `userPrin`, `prinContext`, and `dirEntry`.
13. Return the response sentinel.

## Process flow

```mermaid
flowchart TD
    A["Call AddUser"] --> B{"CheckAccess<br>HasAccess?"}
    B -->|"No"| C["Return AccessDenied<br>Failure"]
    B -->|"Yes"| D["Build CN=Users container path"]
    D --> E["GetUserPrincipal<br>test existence"]
    E -->|"Found"| F["Set UserExists<br>then overwrite Failure"]
    F --> M["Return response"]
    E -->|"Not found"| G["Rebuild context<br>scoped to container"]
    G --> H["New UserPrincipal<br>substitute default password if empty"]
    H --> I["Populate account fields<br>Enabled = True"]
    I --> J["userPrin.Save<br>in Try/Catch"]
    J --> K["Write optional<br>directory attributes"]
    K --> L["dirEntry.CommitChanges<br>in Try/Catch"]
    L --> M
```

## Shared state effects

None — this operation touches no process-wide state; all locals are per-request.

## Error handling

The operation returns a sentinel `ADServiceResponse` for every outcome inside the two `Try` blocks (`Save`, `CommitChanges`). A framework SOAP fault is possible only for a failure outside those blocks — context construction, `New UserPrincipal`, or a property assignment. See [Faults](../faults.md) for the service-wide fault model.

## Authorization

Gated by [BR-01](../business-rules.md#br-01-mutating-and-password-operations-require-an-approved-caller): the caller must pass the IP allow-list check enforced by `CheckAccess`. See [Authentication and authorization](../authentication-authorization.md).

## Related documentation
- [Service index](../index.md)
- [Overview](../overview.md)
- [Architecture](../architecture.md)
- [Activation and hosting](../activation-hosting.md)
- [Operations](../operations.md)
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.md)
- [Authentication and authorization](../authentication-authorization.md)
- [Configuration](../configuration.md)
- [Dependencies](../dependencies.md)
- [Faults](../faults.md)
- [Operational runbook](../operational-runbook.md)
- [Tech debt](../tech-debt.md)

## Sources
- `src\ADUserServices\clsADUserServices.asmx.vb` (lines 91-197)
